/**
 *	\file AKBasicAnimationProvider.m
 *  
 *  \section desc_sec Description
 *  Interface file for animation provider
 *  
 *  \if copyright
 *  	Copyright 2008 Ben Chen. All rights reserved.
 *  \endif
 *  
 *  \section hist_sec Change History:
 *  	-	5/6/08		BC		Created this file
 *  
 *  <hr>
 */

#import "AKBasicAnimationProvider.h"

@implementation AKBasicAnimationProvider

#pragma mark Plug-in properties

- (NSString*)gameName	{ return AKPlugInAnyGame; }
- (NSString*)version	{ return AKMultimediaPlugInAnyVersion; }

#pragma mark Init & dealloc

- (id)init {
	self = [super init];
	if (self != nil) {
		NSNumber *zeroNumber	= [NSNumber numberWithFloat:0.0];
		NSNumber *oneNumber		= [NSNumber numberWithFloat:1.0];
		CGFloat duration		= 0.25;
		
		activationAnimation				= [[CABasicAnimation animationWithKeyPath:@"bounds.size"] retain];		
		activationAnimation.fromValue	= zeroNumber;
		activationAnimation.toValue		= oneNumber;
		activationAnimation.duration	= duration;
		activationAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
		activationAnimation.removedOnCompletion = YES;
		
		deactivationAnimation			= [[CABasicAnimation animationWithKeyPath:@"bounds.size"] retain];
		deactivationAnimation.fromValue = oneNumber;
		deactivationAnimation.toValue	= zeroNumber;
		deactivationAnimation.duration	= duration;
		deactivationAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
		deactivationAnimation.removedOnCompletion = YES;
	}
	return self;
}

- (void)dealloc {
	[activationAnimation release];
	[deactivationAnimation release];
	[super dealloc];
}

#pragma mark Helper functions 

- (CAAnimationGroup*)emergingAnimationForLayer:(CALayer*)aLayer {
	CGFloat totalDuration = 0.5;
	
	// Size animation
	CABasicAnimation *sizeAnimation = [CABasicAnimation animationWithKeyPath:@"bounds.size"];
	sizeAnimation.duration	= totalDuration;
	sizeAnimation.fromValue	= [NSValue valueWithCGSize:CGSizeMake(0, 0)];
	sizeAnimation.toValue	= [NSValue valueWithCGSize:(aLayer.bounds.size)];
	
	// Opacity animation
	CABasicAnimation *opacityAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
	opacityAnimation.duration	= totalDuration;
	opacityAnimation.fromValue	= [NSNumber numberWithFloat:0.0];
	opacityAnimation.toValue	= [NSNumber numberWithFloat:aLayer.opacity];
	
	// Grouping animations
	CAAnimationGroup *retVal	= [CAAnimationGroup animation];
	retVal.animations			= [NSArray arrayWithObjects:sizeAnimation, opacityAnimation, nil];
	retVal.duration				= totalDuration;
	retVal.timingFunction		= [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
	retVal.removedOnCompletion	= YES;
	
	return retVal;	
}

- (CAAnimationGroup*)movingAnimationForLayer:(CALayer*)aLayer startRect:(CGRect)srcRect {
	CGFloat totalDuration = 0.7;
	
	// Keep it at the front most position
	CABasicAnimation *zPozAnimation = [CABasicAnimation animationWithKeyPath:@"zPosition"];
	zPozAnimation.duration	= totalDuration;
	NSNumber *frontMostPoz = [NSNumber numberWithFloat:10000.0];	// TODO: replace 100000 with the max float
	zPozAnimation.fromValue = frontMostPoz;
	zPozAnimation.toValue	= frontMostPoz;
	
	// Size animation
	CABasicAnimation *sizeAnimation = [CABasicAnimation animationWithKeyPath:@"bounds.size"];
	sizeAnimation.duration	= totalDuration;
	sizeAnimation.fromValue	= [NSValue valueWithCGSize:(srcRect.size)];
	sizeAnimation.toValue	= [NSValue valueWithCGSize:(aLayer.bounds.size)];
	
	// Position animation
	CABasicAnimation *pozAnimation	= [CABasicAnimation animationWithKeyPath:@"position"];
	pozAnimation.duration	= totalDuration;
	pozAnimation.fromValue	= [NSValue valueWithCGPoint:CGPointMake(CGRectGetMidX(srcRect), CGRectGetMidY(srcRect)) ];
	pozAnimation.toValue	= [NSValue valueWithCGPoint:CGPointMake(CGRectGetMidX(aLayer.frame), CGRectGetMidY(aLayer.frame))];
	
	// Grouping animations
	CAAnimationGroup *retVal	= [CAAnimationGroup animation];
	retVal.animations			= [NSArray arrayWithObjects:zPozAnimation, sizeAnimation, pozAnimation, nil];
	retVal.duration				= totalDuration;
	retVal.timingFunction		= [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
	retVal.removedOnCompletion	= YES;
	
	return retVal;	
}

- (CAAnimationGroup*)eliminationAnimationForLayer:(CALayer*)aLayer {
	CGFloat totalDuration = 0.5;
	
	// Size animation
	CABasicAnimation *sizeAnimation = [CABasicAnimation animationWithKeyPath:@"bounds.size"];
	sizeAnimation.duration	= totalDuration;
	sizeAnimation.fromValue	= [NSValue valueWithCGSize:(aLayer.bounds.size)];
	sizeAnimation.toValue	= [NSValue valueWithCGSize:CGSizeMake(aLayer.bounds.size.width * 5, aLayer.bounds.size.height * 5)];
	
	// Opacity animation
	CABasicAnimation *opacityAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
	opacityAnimation.duration	= totalDuration;
	opacityAnimation.fromValue	= [NSNumber numberWithFloat:aLayer.opacity];
	opacityAnimation.toValue	= [NSNumber numberWithFloat:0.0];
	
	// zPosition
	CABasicAnimation *zPozAnimation = [CABasicAnimation animationWithKeyPath:@"zPosition"];
	zPozAnimation.duration	= totalDuration;
	NSNumber *frontMostPoz = [NSNumber numberWithFloat:10000.0];	// replace 10000.0 with the max float
	zPozAnimation.fromValue = frontMostPoz;
	zPozAnimation.toValue	= frontMostPoz;
	
	// Grouping animations
	CAAnimationGroup *group = [CAAnimationGroup animation];
	group.animations		= [NSArray arrayWithObjects:sizeAnimation, opacityAnimation, zPozAnimation, nil];
	group.duration			= totalDuration;
	group.timingFunction	= [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
	group.removedOnCompletion = YES;
	
	return group;	
}

#pragma mark Animation Provider methods

- (CAAnimation*)animationForEvent:(NSString*)name piece:(AKPiece)aPiece info:(NSDictionary*)infoDict {
	CAAnimation *retVal = nil;
	CALayer *aLayer = [infoDict valueForKey:kAKAnimationProviderLayerKey];
	
	if ([name isEqualToString:kAKEventPieceActivated]) {
		retVal = activationAnimation;
	} else if ([name isEqualToString:kAKEventPieceDeactivated]) {
		retVal = deactivationAnimation;
	} else if ([name isEqualToString:kAKEventPieceCreated]) {
		retVal = [self emergingAnimationForLayer:aLayer];
	} else if ([name isEqualToString:kAKEventPieceMoved]) {
		CGRect srcRect;
		NSValue *rectValue = [infoDict valueForKey:kAKAnimationProviderStartRectKey];
		[rectValue getValue:&srcRect];
		retVal = [self movingAnimationForLayer:aLayer startRect:srcRect];
	} else if ([name isEqualToString:kAKEventPieceEliminated]) {
		retVal = [self eliminationAnimationForLayer:aLayer];
	}
	
	return retVal;
}

@end
